//
//  IFlyDetection.m
//  Learn
//
//  Created by cjg.mini on 2024/4/7.
//  Copyright © 2024 迟建国. All rights reserved.
//

#import "IFlyDetection.h"

// IFly
#import "IFlyMSC/IFlyMSC.h"
#import "ISEParams.h"
#import "ISEResult.h"
#import "ISEResultXmlParser.h"
#import "PFAudio.h"

@interface IFlyDetection()<IFlySpeechEvaluatorDelegate,IFlyPcmRecorderDelegate,ISEResultXmlParserDelegate>

@property (nonatomic,strong) IFlySpeechEvaluator *iFlySpeechEvaluator;//语音评测类
@property (nonatomic,strong) IFlyPcmRecorder *pcmRecorder;//录音控件
@property (nonatomic,strong) ISEParams *iseParams;//参数

@property (nonatomic,strong) NSString* resultText;

@property (nonatomic,strong) NSMutableData *recordData;

@property (nonatomic,assign) BOOL isBeginOfSpeech; //Whether or not SDK has invoke the delegate methods of beginOfSpeech.

@end

@implementation IFlyDetection

- (instancetype)init {
    if (self = [super init]) {
        // 获取评测对象单例
        self.iFlySpeechEvaluator.delegate = self;
        [self reloadCategoryText];
        
    }
    return self;
}

/// 开始评测
- (void)startEvalutingWord:(NSString*)word {
    
    self.recordData = [NSMutableData new];
    NSString *content = word;
//    if (self.question.type == 6) {
//        self.iseParams.category = KCCategoryChoice;
//    }
    if(self.iseParams.category == KCCategoryWord){
        content = [NSString stringWithFormat:@"[word]\n%@",word];
    }
    if (self.iseParams.category == KCCategorySentence){
        content = [NSString stringWithFormat:@"[content]%@",word];
    }
    if (self.iseParams.category == KCCategoryChoice){
        content = [NSString stringWithFormat:@"[choice]%@",word];
    }
    NSLog(@"&&&&&&&&&&&&&&&&&&&%@",content);
    [self.iFlySpeechEvaluator setParameter:@"16000" forKey:[IFlySpeechConstant SAMPLE_RATE]];
    [self.iFlySpeechEvaluator setParameter:@"utf-8" forKey:[IFlySpeechConstant TEXT_ENCODING]];
    [self.iFlySpeechEvaluator setParameter:@"xml" forKey:[IFlySpeechConstant ISE_RESULT_TYPE]];
    
    [self.iFlySpeechEvaluator setParameter:@"eva.pcm" forKey:[IFlySpeechConstant ISE_AUDIO_PATH]];
    
    NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
    
    NSLog(@"text encoding:%@",[self.iFlySpeechEvaluator parameterForKey:[IFlySpeechConstant TEXT_ENCODING]]);
    NSLog(@"language:%@",[self.iFlySpeechEvaluator parameterForKey:[IFlySpeechConstant LANGUAGE]]);
    
    BOOL isUTF8=[[self.iFlySpeechEvaluator parameterForKey:[IFlySpeechConstant TEXT_ENCODING]] isEqualToString:@"utf-8"];
    BOOL isZhCN=[[self.iFlySpeechEvaluator parameterForKey:[IFlySpeechConstant LANGUAGE]] isEqualToString:KCLanguageZHCN];
    
    BOOL needAddTextBom=isUTF8&&isZhCN;
    NSMutableData *buffer = nil;
    if(needAddTextBom){
        if(content && [content length]>0){
            Byte bomHeader[] = { 0xEF, 0xBB, 0xBF };
            buffer = [NSMutableData dataWithBytes:bomHeader length:sizeof(bomHeader)];
            [buffer appendData:[content dataUsingEncoding:NSUTF8StringEncoding]];
            DebugLog(@" \ncn buffer length: %lu",(unsigned long)[buffer length]);
        }
    }
    else{
        buffer= [NSMutableData dataWithData:[content dataUsingEncoding:encoding]];
        DebugLog(@" \nen buffer length: %lu",(unsigned long)[buffer length]);
    }
    
    
    BOOL ret = [self.iFlySpeechEvaluator startListening:buffer params:nil];
    if(ret){
        //Set audio stream as audio source,which requires the developer import audio data into the recognition control by self through "writeAudio:".
        if ([self.iseParams.audioSource isEqualToString:IFLY_AUDIO_SOURCE_STREAM]){
            
            _isBeginOfSpeech = NO;
            [IFlyAudioSession initRecordingAudioSession];
            
            self.pcmRecorder.delegate = self;
            [self.pcmRecorder setSaveAudioPath:[[self.question.recordPath stringByDeletingPathExtension] stringByAppendingString:@".pcm"]];
            //start recording
            BOOL ret = [_pcmRecorder start];
            
            NSLog(@"%s[OUT],Success,Recorder ret=%d",__func__,ret);
        }
    }
    
}

- (void)cancle {
    if ([self.iseParams.audioSource isEqualToString:IFLY_AUDIO_SOURCE_STREAM] && !_isBeginOfSpeech){
        DebugLog(@"%s,stop recording",__func__);
        [_pcmRecorder stop];
    }
    
    [self.iFlySpeechEvaluator cancel];
}

- (void)stop {
    
    [_pcmRecorder stop];
    [self.iFlySpeechEvaluator stopListening];//音频数据写入完成，进入等待状态
//    NSError *error;
//    NSString *url = [[self.question.recordPath stringByDeletingPathExtension] stringByAppendingString:@".pcm"];
//   
//    if (self.recordData.length > 0) {
//        BOOL success = [self.recordData writeToFile:url options:NSDataWritingAtomic error:&error];
//        if (!success) {
//            NSLog(@"保存音频文件失败：%@", error.localizedDescription);
//        } else {
//            [PFAudio pcm2Mp3:url isDeleteSourchFile:YES];
//            NSLog(@"音频文件保存成功：%@", self.question.recordPath);
//        }
//    }
}

- (void)evalutLanguage:(NSUInteger)language {
    switch (language) {
        case 0: {
            if(![self.iseParams.rstLevel isEqualToString:KCRstLevelPlain]){//Plain is not supported in Chinese
                self.iseParams.language = KCLanguageZHCN;
                self.iseParams.languageShow = @"K_LangCHZN";
            }
            else{
                self.iseParams.language = KCLanguageENUS;
                self.iseParams.languageShow = @"K_LangEng";
            }
        }
            break;
            
        case 1: {
            if(![self.iseParams.category isEqualToString:KCCategorySyllable]){//Syllable is not supported in English
                self.iseParams.language = KCLanguageENUS;
                self.iseParams.languageShow = @"K_LangEng";
            }
        }
            break;
    }
    [self reloadCategoryText];
    
}

- (void)evalutType:(NSUInteger)type {
    switch (type) {
        case 0: {
            self.iseParams.category = KCCategorySentence;
            self.iseParams.categoryShow = @"K_ISE_CateSent";
        }
            break;
            
        case 1: {
            self.iseParams.category = KCCategoryWord;
            self.iseParams.categoryShow = @"K_ISE_CateWord";
        }
            break;
            
        case 2: {
            self.iseParams.category = KCCategoryChapter;
            self.iseParams.categoryShow = @"K_ISE_CateChapter";
        }
            break;
        case 3: {
            if(![self.iseParams.language isEqualToString:KCLanguageENUS]){//Syllable is not supported in English
                self.iseParams.category = KCCategorySyllable;
                self.iseParams.categoryShow = @"K_ISE_CateSyll";
            }
            else {
                self.iseParams.category = KCCategoryExpression;
                self.iseParams.categoryShow = @"K_ISE_CateExpression";
            }
        }
            break;
        case 4: {
            if([self.iseParams.language isEqualToString:KCLanguageENUS]){//Syllable is not supported in English
                self.iseParams.category = KCCategoryChoice;
                self.iseParams.categoryShow = @"K_ISE_CateChoice";
            }
        }
            break;
        case 5: {
            if([self.iseParams.language isEqualToString:KCLanguageENUS]){//Syllable is not supported in English
                self.iseParams.category = KCCategoryTopic;
                self.iseParams.categoryShow = @"K_ISE_CateTopic";
            }
        }
            break;
        case 6: {
            if([self.iseParams.language isEqualToString:KCLanguageENUS]){//Syllable is not supported in English
                self.iseParams.category = KCCategoryRetell;
                self.iseParams.categoryShow = @"K_ISE_CateRetell";
            }
        }
            break;
        case 7: {
            if([self.iseParams.language isEqualToString:KCLanguageENUS]){//Syllable is not supported in English
                self.iseParams.category = KCCategoryPictureTalk;
                self.iseParams.categoryShow = @"K_ISE_CatePictureTalk";
            }
        }
            break;
        case 8: {
            if([self.iseParams.language isEqualToString:KCLanguageENUS]){//Syllable is not supported in English
                self.iseParams.category = KCCategoryOralTranslation;
                self.iseParams.categoryShow = @"K_ISE_CateOralTrans";
            }
        }
            
            break;
            
    }
    [self reloadCategoryText];
    
}

- (void)evalutSource:(NSUInteger)source {
    switch (source) {
        case 0: {
            self.iseParams.audioSource = KCSourceMIC;
        }
            break;
            
        case 1: {
            self.iseParams.audioSource = KCSourceSTREAM;
        }
            break;
    }
    [self reloadCategoryText];
    
}

-(void)reloadCategoryText{
    
    // updated ise_flow
    [self.iFlySpeechEvaluator setParameter:@"ise" forKey:@"sub"];
    [self.iFlySpeechEvaluator setParameter:@"0" forKey:@"plev"];
    [self.iFlySpeechEvaluator setParameter:@"1" forKey:@"ise_unite"];
    [self.iFlySpeechEvaluator setParameter:@"entirety" forKey:@"rst"];
    [self.iFlySpeechEvaluator setParameter:@"syll_phone_err_msg;pitch;multi_dimension" forKey:@"extra_ability"];
    
    [self.iFlySpeechEvaluator setParameter:@"300000" forKey:[IFlySpeechConstant VAD_BOS]];
    [self.iFlySpeechEvaluator setParameter:@"300000" forKey:[IFlySpeechConstant VAD_EOS]];
    [self.iFlySpeechEvaluator setParameter:self.iseParams.category forKey:[IFlySpeechConstant ISE_CATEGORY]];
    [self.iFlySpeechEvaluator setParameter:self.iseParams.language forKey:[IFlySpeechConstant LANGUAGE]];
    [self.iFlySpeechEvaluator setParameter:self.iseParams.rstLevel forKey:[IFlySpeechConstant ISE_RESULT_LEVEL]];
    [self.iFlySpeechEvaluator setParameter:@"300000" forKey:[IFlySpeechConstant SPEECH_TIMEOUT]];
    [self.iFlySpeechEvaluator setParameter:self.iseParams.audioSource forKey:[IFlySpeechConstant AUDIO_SOURCE]];
    
    if ([self.iseParams.language isEqualToString:KCLanguageZHCN]) {
        
        [self.iFlySpeechEvaluator setParameter:@"cn_vip" forKey:@"ent"]; // updated ise_flow
        
    }
    else {
        
        [self.iFlySpeechEvaluator setParameter:@"en_vip" forKey:@"ent"]; // updated ise_flow
        
    }
}


#pragma mark - IFlySpeechEvaluatorDelegate

// 音量和数据回调
- (void)onVolumeChanged:(int)volume buffer:(NSData *)buffer {
    DebugLog(@"volume:%d",volume);
    [self.recordData appendData:buffer];
}

// 开始录音回调
- (void)onBeginOfSpeech {
    if ([self.iseParams.audioSource isEqualToString:IFLY_AUDIO_SOURCE_STREAM]){
        _isBeginOfSpeech =YES;
    }
    
}

// 停止录音回调
- (void)onEndOfSpeech {
    if ([self.iseParams.audioSource isEqualToString:IFLY_AUDIO_SOURCE_STREAM]){
        [_pcmRecorder stop];
        
    }
    
}

// 会话取消回调
- (void)onCancel {
    
}

// 评测错误回调
- (void)onCompleted:(IFlySpeechError *)errorCode {
    DebugLog(@"errorCode :%@",errorCode.errorDesc);
    if (self.delegate && [self.delegate respondsToSelector:@selector(onCompleted:)]) {
        [self.delegate onCompleted:errorCode];
    }
}

// 评测结果回调
- (void)onResults:(NSData *)results isLast:(BOOL)isLast {
    
    DebugLog(@"results :%@",results);
   
    if (results) {
        NSString *showText = @"";
        
        const char* chResult=[results bytes];
        
        BOOL isUTF8=[[self.iFlySpeechEvaluator parameterForKey:[IFlySpeechConstant RESULT_ENCODING]] isEqualToString:@"utf-8"];
        NSString* strResults=nil;
        if(isUTF8){
            strResults=[[NSString alloc] initWithBytes:chResult length:[results length] encoding:NSUTF8StringEncoding];
        } else {
            DebugLog(@"result encoding: gb2312");
            NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
            strResults=[[NSString alloc] initWithBytes:chResult length:[results length] encoding:encoding];
        }
        if(strResults){
            showText = [showText stringByAppendingString:strResults];
            self.resultText=showText;
        }
        DebugLog(@"showText ：%@",showText);
        [self saveFile];
        // 处理评测结果 -- 解析
        ISEResultXmlParser* parser=[[ISEResultXmlParser alloc] init];
        parser.delegate=self;
        [parser parserXml:self.resultText];
    }
}
- (void)xmlDeal:(NSData *)data
{
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    ISEResultXmlParser* parser=[[ISEResultXmlParser alloc] init];
    parser.delegate=self;
    [parser parserXml:str];
}
- (void)saveFile
{
    NSError *error;
    NSString *url = [[self.question.recordPath stringByDeletingPathExtension] stringByAppendingString:@".pcm"];
    if ([[NSFileManager defaultManager] fileExistsAtPath:url]) {
        [[NSFileManager defaultManager] removeItemAtPath:url error:&error];
    }
    if ([[NSFileManager defaultManager] fileExistsAtPath:self.question.recordPath]) {
        [[NSFileManager defaultManager] removeItemAtPath:self.question.recordPath error:&error];
    }
    BOOL success = [self.recordData writeToFile:url options:NSDataWritingAtomic error:&error];
    if (!success) {
        NSLog(@"保存音频文件失败：%@", error.localizedDescription);
    } else {
        [PFAudio pcm2Mp3:url isDeleteSourchFile:YES];
        NSLog(@"音频文件保存成功：%@", self.question.recordPath);
    }
}
#pragma mark - IFlyPcmRecorderDelegate

// 回调音频数据
- (void) onIFlyRecorderBuffer: (const void *)buffer bufferSize:(int)size {
    
    NSData *audioBuffer = [NSData dataWithBytes:buffer length:size];
    [self.recordData appendData:audioBuffer];
    //写入音频，让SDK评测。建议将音频数据分段写入
    int ret = [self.iFlySpeechEvaluator writeAudio:audioBuffer];
    
    if (!ret) {
        [self stop];
    }
}

// 回调音频的错误码
- (void) onIFlyRecorderError:(IFlyPcmRecorder*)recoder theError:(int) error {
    
}

// 回调录音音量 （ 0 ～ 30 ）
- (void) onIFlyRecorderVolumeChanged:(int) power {
    
    DebugLog(@"power:%@",@(power));
    
}

#pragma mark - ISEResultXmlParserDelegate

-(void)onISEResultXmlParser:(NSXMLParser *)parser Error:(NSError*)error {
    DebugLog(@"onISEResultXmlParser");
}

-(void)onISEResultXmlParserResult:(ISEResult*)result {
    NSLog(@"GGGGGGGGGG%@",[result toString]);
    if (self.delegate && [self.delegate respondsToSelector:@selector(evaluting:result:)]) {
        [self.delegate evaluting:self result:[result toString]];
    }
}

#pragma mark - setter & getter
//录音控件
- (IFlyPcmRecorder *)pcmRecorder {
    if (!_pcmRecorder) {
        _pcmRecorder = [IFlyPcmRecorder sharedInstance];
        _pcmRecorder.delegate = self;
        [_pcmRecorder setSample:@"16000"];
    }
    return _pcmRecorder;
}

//评测对象参数配置
- (ISEParams *)iseParams {
    if (!_iseParams) {
        _iseParams = [ISEParams fromUserDefaults];
        _iseParams.category = KCCategorySentence;
    }
    return _iseParams;
}

//评测对象
- (IFlySpeechEvaluator *)iFlySpeechEvaluator {
    if (!_iFlySpeechEvaluator) {
        _iFlySpeechEvaluator = [IFlySpeechEvaluator sharedInstance];
        
    }
    return _iFlySpeechEvaluator;
}

@end
